package com.example.servicetest.ui.clip_image

import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.MotionEvent.INVALID_POINTER_ID
import android.view.View
import com.example.servicetest.R
import kotlin.math.abs
import kotlin.math.roundToInt
import kotlin.math.sqrt

/**
 * 自定义的裁剪区域框
 * 参考https://blog.csdn.net/WPR13005655989/article/details/127093551
 */
class ClipImageView:View {

    private val mPorterDuffXfermode = PorterDuffXfermode(PorterDuff.Mode.DST_OUT)

    private val mPaint = Paint()

    private val mPaintX = Paint()

    private val mBgBitmapSrcRect:Rect = Rect()

    /**
     * 背景绘制区域,同时也是裁剪区域
     */
    private val mBgBitmapDstRect:Rect = Rect()

    /**
     * 缩放后目标图标区域
     */
    private val mScaleBitmapDstRect:Rect = Rect()

    /**
     * 未缩放的目标图标区域
     */
    private val mScaleBitmapSrcRect:Rect = Rect()

    /**
     * 目标图片
     */
    private var mScaleBitmap: Bitmap? = null

    /**
     * 镂空的图层
     */
    private var mBgBitmap: Bitmap = BitmapFactory.decodeResource(resources, R.drawable.preview)

    private val MIN_THRESHOLD = 2

    val zoomCenterPoint = doubleArrayOf(0.0, 0.0)

    private val translateStartPoint = doubleArrayOf(0.0, 0.0)

    var lastDistance = 0.0

    //通过官方文档描述，需要记录下当前的默认手指Id
    private var mActivePointerId = INVALID_POINTER_ID

    var xDiff = 0.0
    var yDiff = 0.0

    constructor(context: Context) : this(context, null)
    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    ){
        setBackgroundColor(Color.BLACK)
        setLayerType(LAYER_TYPE_SOFTWARE,null)
        mPaint.run {
            isAntiAlias = true
        }
        mPaintX.xfermode = mPorterDuffXfermode
    }

    fun setScaleBitmap(bitmap: Bitmap){
        this.mScaleBitmap = bitmap
        mScaleBitmap?.run {
            mScaleBitmapSrcRect.also {
                it.top = 0
                it.left = 0
                it.right = width
                it.bottom = height
            }
            if(width>=height){
                val ratio = width/height.toFloat()
                val newBitmapHeight = this@ClipImageView.width/ratio
                mScaleBitmapDstRect.also {
                    it.left = 0
                    it.top = ((this@ClipImageView.height - newBitmapHeight)/2).roundToInt()
                    it.right = this@ClipImageView.width
                    it.bottom = it.top+newBitmapHeight.roundToInt()
                }
            }else{
                val ratio = width/height.toFloat()
                val newBitmapWith = this@ClipImageView.height*ratio
                mScaleBitmapDstRect.also {
                    it.top = 0
                    it.left = ((this@ClipImageView.width - newBitmapWith)/2).roundToInt()
                    it.right = (it.left + newBitmapWith ).roundToInt()
                    it.bottom = this@ClipImageView.height
                }
            }
        }
        invalidate()
    }

    fun saveCupImage():Bitmap{
        val bitmap = Bitmap.createBitmap(
            this.width,
            this.height,
            Bitmap.Config.ARGB_8888,
        )
        val canvas = Canvas(bitmap)
        canvas.drawBitmap(mScaleBitmap!!,mScaleBitmapSrcRect,mScaleBitmapDstRect, null)
        return Bitmap.createBitmap(
            bitmap,mBgBitmapDstRect.left,
            mBgBitmapDstRect.top,
            mBgBitmapDstRect.right-mBgBitmapDstRect.left,
            mBgBitmapDstRect.bottom-mBgBitmapDstRect.top
        )
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        when(event.actionMasked){
            MotionEvent.ACTION_DOWN->{
                //第一个手指按下，把这个Id记录下来，并且把其坐标作为起始点击坐标
                event.actionIndex.also { pointerIndex ->
                    val findPointerIndex = event.findPointerIndex(pointerIndex)
                    translateStartPoint[0] = event.getX(findPointerIndex).toDouble()
                    translateStartPoint[1] = event.getY(findPointerIndex).toDouble()
                }
                mActivePointerId = event.getPointerId(0)
            }
            MotionEvent.ACTION_MOVE->{
                val translateEndPoint = doubleArrayOf(0.0, 0.0)
                //拖放结束点先用默认手指的当前位置
                event.findPointerIndex(mActivePointerId).let { pointerIndex ->
                    translateEndPoint[0] = event.getX(pointerIndex).toDouble()
                    translateEndPoint[1] = event.getY(pointerIndex).toDouble()
                }
                //如果多点触控，我们要计算两个手指的中心点作为终点
                if (event.pointerCount >= 2) {
                    calculateCenter(event).also {
                        zoomCenterPoint[0] = it[0]
                        zoomCenterPoint[1] = it[1]

                        translateEndPoint[0] = it[0]
                        translateEndPoint[1] = it[1]
                    }
                    val currentDistance = spacing(event)
                    val distanceDiff = currentDistance - lastDistance
                    if (abs(distanceDiff) > MIN_THRESHOLD) {
                        //把事件去控制比例尺缩放
                        mScaleBitmapDstRect.also {
                            it.left = (it.left - distanceDiff).roundToInt()
                            it.top = (it.top - distanceDiff).roundToInt()
                            it.right = (it.right + distanceDiff).roundToInt()
                            it.bottom = (it.bottom + distanceDiff).roundToInt()
                        }
                        lastDistance = currentDistance
                        invalidate()
                    }
                }
                //计算x、y方向的平移量
                 xDiff = translateEndPoint[0] - translateStartPoint[0]
                 yDiff = translateEndPoint[1] - translateStartPoint[1]

                if (abs(xDiff) > MIN_THRESHOLD || abs(yDiff) > MIN_THRESHOLD) {
                    //把事件控制平移
                    mScaleBitmapDstRect.also {
                        it.left = (it.left + xDiff).roundToInt()
                        it.top = (it.top + yDiff).roundToInt()
                        it.right = (it.right + xDiff).roundToInt()
                        it.bottom = (it.bottom + yDiff).roundToInt()
                    }
                    invalidate()
                }
                translateStartPoint[0] = translateEndPoint[0]
                translateStartPoint[1] = translateEndPoint[1]
            }
            MotionEvent.ACTION_UP,
            MotionEvent.ACTION_CANCEL->{
                mActivePointerId = INVALID_POINTER_ID
            }
            MotionEvent.ACTION_POINTER_UP->{
                //多点触摸的时候，当有一个手指抬起时，会触发这个Action，我们需要判断，抬起的手指是不是
                //当前记录的第一个手指的Id，如果是，说明默认的手指Id已经发生变化，变成另一个了，所以
                //我们的平移基准点坐标也要改变成变成另一个，否则会出现松开第一种手指时，没有进行拖拽却计算到很大的平移距离的问题，这里也是参考官方文档解释后发现的问题
                event.actionIndex.also { pointerIndex ->
                    val pointerId = event.getPointerId(pointerIndex)
                    if (pointerId == mActivePointerId) {
                        val newPointerIndex = if (pointerIndex == 0) 1 else 0
                        translateStartPoint[0] = event.getX(newPointerIndex).toDouble()
                        translateStartPoint[1] = event.getY(newPointerIndex).toDouble()
                        //重新设置默认手指的id 保证取的坐标没问题
                        mActivePointerId = event.getPointerId(newPointerIndex)
                    } else {
                        //松开的不是第一个按下的手指，直接把基准点重置成第一个手指的坐标
                        translateStartPoint[0] =
                            event.getX(event.findPointerIndex(mActivePointerId)).toDouble()
                        translateStartPoint[1] =
                            event.getY(event.findPointerIndex(mActivePointerId)).toDouble()
                    }
                }
            }

            MotionEvent.ACTION_POINTER_DOWN->{
                //第二个以上手指按下，计算两个手指之间的中心位置，因为我们要实现缩放的同时支持平移，
                //所以，一个手指按下时，平移的基点就是这个手指的坐标，两个手指按下时，我们就以两个手指的中心
                //点坐标作为基点，同时也以这个基点作为缩放的基准点
                calculateCenter(event).also {
                    zoomCenterPoint[0] = it[0]
                    zoomCenterPoint[1] = it[1]
                    translateStartPoint[0] = it[0]
                    translateStartPoint[1] = it[1]
                }
                //计下按下时两个手指的直线距离，为双指缩放准备
                lastDistance = spacing(event)
            }
        }
        return true
    }

    /**
     * 计算连个手指连线中心点
     */
    private fun calculateCenter(event: MotionEvent): DoubleArray {
        //计算起点中心坐标
        val x0 = event.getX(0)
        val y0 = event.getY(0)

        val x1 = event.getX(1)
        val y1 = event.getY(1)

        return doubleArrayOf(
            x0 + (x1 - x0) / 2.0,
            y0 + (y1 - y0) / 2.0
        )
    }

    /**
     * 计算两个点的距离
     *
     * @param event
     * @return
     */
    private fun spacing(event: MotionEvent): Double {
        return if (event.pointerCount == 2) {
            val x = event.getX(0) - event.getX(1)
            val y = event.getY(0) - event.getY(1)
            sqrt((x * x + y * y).toDouble())
        } else 0.0
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        //裁剪区域取宽度的0.7,也就是人脸图片的宽度,计算比例获取人脸的绘制区域
        val newBgBitmapWidth = width-width*0.3
        val ratio = mBgBitmap.width/mBgBitmap.height.toFloat()
        val newBgBitmapHeight = newBgBitmapWidth/ratio
        mBgBitmapDstRect.run {
            left = ((width - newBgBitmapWidth)/2).roundToInt()
            top = ((height - newBgBitmapHeight)/2).roundToInt()
            right = (left+newBgBitmapWidth).roundToInt()
            bottom = (top + newBgBitmapHeight).roundToInt()
        }
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        //绘制目标图片
        mPaint.color = Color.parseColor("#000000")
        mScaleBitmap?.run {
            canvas.drawBitmap(mScaleBitmap!!,mScaleBitmapSrcRect,mScaleBitmapDstRect, null)
        }
        val id = canvas.saveLayer(0f,0f, width.toFloat(), height.toFloat(), null)
        //绘制背景蒙版
        mPaint.color = Color.parseColor("#66000000")
        mBgBitmapSrcRect.run {
            top = 0
            left = 0
            right = width
            bottom = height
        }
        canvas.drawRect(mBgBitmapSrcRect,mPaint)
        //绘制人脸
        mBgBitmapSrcRect.run {
            left = 0
            top = 0
            right = mBgBitmap.width
            bottom = mBgBitmap.height
        }
        //居中绘制
        canvas.drawBitmap(mBgBitmap,mBgBitmapSrcRect,mBgBitmapDstRect,mPaintX)
        canvas.restoreToCount(id)
    }

}
